package main

import (
	"flag"
	"fmt"
	"io"
	"net"
	"os"
)

type Clinet struct {
	ServerIP   string
	ServerPort int
	Name       string
	conn       net.Conn
	choice     int // 当前Client的模式
}

func NewClient(serverIp string, serverPort int) *Clinet {
	client := &Clinet{
		ServerIP:   serverIp,
		ServerPort: serverPort,
		choice:     999,
	}

	conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", serverIp, serverPort))
	if err != nil {
		fmt.Println("连接失败:", err)
		return nil
	}

	client.conn = conn

	return client
}

// 处理server回应的消息， 直接显示到标准输出即可
func (client *Clinet) DialResponse() {
	// 一旦client.conn有数据，就直接copy到stdout标准输出上, 永久阻塞监听
	io.Copy(os.Stdout, client.conn)
}

func showMenu() {
	fmt.Println("1.群聊模式")
	fmt.Println("2.私聊模式")
	fmt.Println("3.修改用户名")
	fmt.Println("4.查看当前在线用户")
	fmt.Println("0.退出")
}

func (client *Clinet) menu() bool {
	var choice int

	showMenu()

	fmt.Scanln(&choice)

	if choice >= 0 && choice <= 4 {
		client.choice = choice
		return true
	} else {
		fmt.Println(">>>> 请输入合法范围内的数字<<<<")
		return false
	}
}

func (client *Clinet) PublicChat() {
	var inputMsg string
	fmt.Println(">>>> 请输入聊天内容，q退出:")
	fmt.Scanln(&inputMsg)

	for inputMsg != "q" {
		if len(inputMsg) != 0 {
			_, err := client.conn.Write([]byte(inputMsg + "\n"))
			if err != nil {
				fmt.Println("发送失败：", err)
				break
			}
		}

		inputMsg = ""
		fmt.Println(">>>> 请输入聊天内容，q退出:")
		fmt.Scanln(&inputMsg)
	}
}

// 获取当前在线用户
func (client *Clinet) GetOnlineUsers() {
	_, err := client.conn.Write([]byte("who are online\n"))
	if err != nil {
		fmt.Println("查询失败：", err)
		return
	}
}

func (client *Clinet) PrivateChat() {
	var remoteName string
	var inputMsg string

	client.GetOnlineUsers()
	fmt.Println(">>>> 请输入聊天对象[用户名]，q退出:")
	fmt.Scanln(&remoteName)

	for remoteName != "q" {
		fmt.Println(">>>> 请输入聊天内容，q退出:")
		fmt.Scanln(&inputMsg)

		for inputMsg != "q" {
			if len(inputMsg) != 0 {
				_, err := client.conn.Write([]byte(inputMsg + "\n"))
				if err != nil {
					fmt.Println("发送失败：", err)
					break
				}
			}

			inputMsg = ""
			fmt.Println(">>>> 请输入聊天内容，q退出:")
			fmt.Scanln(&inputMsg)
		}

		client.GetOnlineUsers()
		fmt.Println(">>>> 请输入聊天对象[用户名]，q退出:")
		fmt.Scanln(&remoteName)
	}
}

func (client *Clinet) UpdateName() bool {
	fmt.Println(">>>> 请输入新用户名:")
	fmt.Scanln(&client.Name)

	sendMsg := "rename|" + client.Name + "\n"
	_, err := client.conn.Write([]byte(sendMsg))
	if err != nil {
		fmt.Println("修改失败：", err)
		return false
	}
	return true
}

func (client *Clinet) Run() {
	for client.choice != 0 {
		for !client.menu() {
		}

		switch client.choice {
		case 1:
			// 群聊
			client.PublicChat()
			break
		case 2:
			// 私聊
			client.PrivateChat()
			break
		case 3:
			// 更新用户名
			client.UpdateName()
			break
		case 4:
			// 获取当前在线用户
			client.GetOnlineUsers()
			break
		}
	}
}

var serverIp string
var serverPort int

func init() {
	flag.StringVar(&serverIp, "ip", "127.0.0.1", "设置服务器IP地址(默认是127.0.0.1)")
	flag.IntVar(&serverPort, "port", 8888, "设置服务器端口(默认是8888)")
}

func main() {
	flag.Parse()

	client := NewClient(serverIp, serverPort)
	serverAddr := fmt.Sprintf("%s:%d", serverIp, serverPort)
	if client == nil {
		fmt.Println(">>>> 连接服务器" + serverAddr + "失败...")
		return
	}

	// 服务器返回的消息直接输出到窗口
	go client.DialResponse()

	fmt.Println(">>>> 连接服务器" + serverAddr + "成功...")

	client.Run()
}
